/**
 * 客户端项目模型
 *
 * Created by snowingsea on 2020/02/08.
 */
const request = require('request-promise');
const querystring = require('querystring');
const randomstring = require('randomstring');
const fs = require('fs');
const { statusKind, versionType } = require('./../../phoenix/models/project-versions');
const ProjectVersion = require('./project-version');
const File = require('./file');

const testerURI = require('./../api/tester/uri');

class Project {
  /**
   * @param {User} creator 创建者
   * @param {String} projectId 项目id
   * @param {String} projectName 项目名
   * @param {Number} status 项目状态
   * @param {ProjectVersion} lastVersion 最新版本
   */
  constructor(creator, projectId, projectName, status, lastVersion = undefined) {
    this.creator = creator;
    this.projectName = projectName;
    this.projectId = projectId;
    this.status = status;
    this.lastVersion = lastVersion;
  }

  /**
   * 获取项目版本信息
   * @param {Object} versionId 版本id
   * @return {Promise}
   */
  getVersion(versionId) {
    return new Promise((resolve, reject) => {
      let version;
      this.creator.login()
        .then(() => {
          const options = {
            url: `${testerURI}/project-versions/${versionId}.json`,
            headers: { Authorization: `Bearer ${this.creator.token.accessToken}` },
            json: true,
          };
          return request.get(options);
        })
        .then((res) => {
          version = res;
          return this.creator.logout();
        })
        .then(() => {
          resolve(version);
        })
        .catch(reject);
    });
  }

  /**
   * 获取当前项目的版本总数
   * @param {Object} filter 筛选器
   * @return {Promise}
   */
  getVersionTotalNumber(filter = {}) {
    return new Promise((resolve, reject) => {
      let totalNumber = 0;
      this.creator.login()
        .then(() => {
          const url = `${testerURI}/projects/${this.projectId}/versions.json?${querystring.stringify(filter)}`;
          return request.get({
            url,
            headers: { Authorization: `Bearer ${this.creator.token.accessToken}` },
            json: true,
          });
        })
        .then(({ pagination }) => {
          totalNumber = pagination.total;
          return this.creator.logout();
        })
        .then(() => {
          resolve(totalNumber);
        })
        .catch(reject);
    });
  }

  /**
   * 登录状态下创建项目版本
   * @param {Object} versionInfo 项目版本信息
   * @return {Promise}
   */
  createVersion(versionInfo) {
    return new Promise((resolve, reject) => {
      const options = {
        url: `${testerURI}/projects/${this.projectId}/versions.json?${querystring.stringify(versionInfo)}`,
        headers: { Authorization: `Bearer ${this.creator.token.accessToken}` },
        json: true,
      };
      request.post(options)
        .then((res) => {
          const version = new ProjectVersion(this, res.versionId, res.versionName, res.status);
          const {
            fileId,
            path,
            status,
            kind,
          } = res.rootDirectory;
          version.rootDirectory = new File(version, fileId, path, status, kind);
          resolve(version);
        })
        .catch(reject);
    });
  }

  /**
   * 登录状态下创建回归版本
   * @param {Number} type 文件上传方式 1：本地上传
   * @param {String} versionName 版本名称
   * @param {String} oldVersionId 原始版本id
   * @param {String} filePath 绝对地址路径
   * @returns
   */
  createRegressionVersion(type = 1, versionName, oldVersionId, filePath) {
    return new Promise((resolve, reject) => {
      const options = {
        url: `${testerURI}/projects/${this.projectId}/regression/versions.json?type=${type}&versionName=${versionName}&oldVersionId=${oldVersionId}`,
        headers: { Authorization: `Bearer ${this.creator.token.accessToken}` },
        json: true,
        formData: {
          file: fs.createReadStream(filePath),
        },
      };
      request.post(options)
        .then((resFile) => this.getVersion(resFile.versionId))
        .then((res) => {
          const version = new ProjectVersion(this, res.versionId, res.versionName, res.status, undefined, oldVersionId);
          const {
            fileId,
            path,
            status,
            kind,
          } = res.rootDirectory;
          version.rootDirectory = new File(version, fileId, path, status, kind);
          resolve(version);
        })
        .catch(reject);
    });
  }

  createRandomIntegrationVersion(filePath, config = {}, language = 'c') {
    const that = this;
    let masterVersion;
    return this.createRandomVersion(language)
      .then((projectVersion) => {
        masterVersion = projectVersion;
        return projectVersion.updateVersionFiles(filePath, config);
      })
      .then(() => masterVersion.initSubVersion(
        masterVersion.versionId,
        versionType.integrationTest
      ))
      // 更新默认打桩层级
      .then((subVersion) => {
        const options = {
          url: `${testerURI}/project-versions/${subVersion.versionId}.json`,
          headers: { Authorization: `Bearer ${this.creator.token.accessToken}` },
          body: { integrationTest: { stubDepth: 10 } },
          json: true,
        };
        return request.put(options);
      })
      .then((res) => that.getVersion(res.versionId))
      .then((res) => {
        const version = new ProjectVersion(this, res.versionId, res.versionName, res.status);
        const {
          fileId,
          path,
          status,
          kind,
        } = res.rootDirectory;
        version.masterVersionId = res.masterVersionId;
        version.rootDirectory = new File(version, fileId, path, status, kind);
        return version;
      });
  }

  createIntegrationTestStaticAnalyzeVersion(masterVersionId) {
    let projectVersion;
    let staticAnalyzeTestVersion;
    const that = this;
    return this.getVersion(masterVersionId)
      .then((res) => {
        projectVersion = new ProjectVersion(that, masterVersionId, res.versionName, res.status);
        return projectVersion.initSubVersion(
          masterVersionId,
          versionType.staticAnalyze
        );
      }).then((res) => that.getVersion(res.versionId))
      .then((res) => {
        staticAnalyzeTestVersion = res;
        // return user.createTemplate(rules);
      })
      // .then((template) => projectVersion.linkAnalyzeTemplate(template._id.toString()))
      .then(() => {
        const version = new ProjectVersion(
          that,
          staticAnalyzeTestVersion.versionId,
          staticAnalyzeTestVersion.versionName,
          staticAnalyzeTestVersion.status
        );
        const {
          fileId,
          path,
          status,
          kind,
        } = staticAnalyzeTestVersion.rootDirectory;
        version.rootDirectory = new File(version, fileId, path, status, kind);
        return version;
      });
  }

  /**
   * 随机创建版本
   * @return {Promise}
   */
  createRandomVersion(language = 'c') {
    return new Promise((resolve, reject) => {
      let projectVersion;
      this.creator.login()
        .then(() => this.createVersion(ProjectVersion.getRandomProjectVersionInfo(language)))
        .then((res) => {
          projectVersion = res;
          return this.creator.logout();
        })
        .then(() => {
          resolve(projectVersion);
        })
        .catch(reject);
    });
  }

  /**
   * 批量创建随机项目版本
   * @param {Number} count 创建个数
   * @param {String} language 项目类型
   * @return {Promise}
   */
  createRandomVersions(count = 10, language = 'c') {
    return new Promise((resolve, reject) => {
      const versions = [];
      const that = this;
      function step(index) {
        if (index >= count) {
          resolve(versions);
          return;
        }
        that.createRandomVersion(language)
          .then((res) => {
            versions.push(res);
            step(index + 1);
          })
          .catch(reject);
      }
      step(0);
    });
  }

  /**
   * 创建静态分析版本
   * @param {Array<String>} rules 模板关联的规则
   * @param {String} zip 检测文件zip包
   * @param {Object} user 用户
   * @return {Object}
   */
  createStaticAnalyzeVersion(rules, zip, user) {
    let analyzeTemplate;
    let projectVersion;
    let masterVersion;
    const that = this;
    return user.createTemplate(rules)
      .then((template) => {
        analyzeTemplate = template;
        return that.createRandomVersion('c++');
      })
      .then((res) => {
        masterVersion = res;
        return res.initSubVersion(res.versionId, versionType.staticAnalyze);
      })
      .then((res) => that.getVersion(res.versionId))
      .then((res) => {
        projectVersion = new ProjectVersion(this, res.versionId, res.versionName, res.status);
        const {
          fileId,
          path,
          status,
          kind,
        } = res.rootDirectory;
        projectVersion.rootDirectory = new File(projectVersion, fileId, path, status, kind);
        projectVersion.masterVersionId = masterVersion.versionId;
        return projectVersion.linkAnalyzeTemplate(analyzeTemplate._id.toString());
      })
      .then(() => projectVersion.updateVersionFiles(zip))
      .then(() => projectVersion);
  }

  /**
   * 删除项目版本
   * @param {String} versionId 版本id
   * @return {Promise}
   */
  removeVersion(versionId) {
    return new Promise((resolve, reject) => {
      this.creator.login()
        .then(() => {
          const url = `${testerURI}/project-versions/${versionId}.json`;
          return request.delete({
            url,
            headers: { Authorization: `Bearer ${this.creator.token.accessToken}` },
          });
        })
        .then(() => this.creator.logout())
        .then(() => {
          resolve();
        })
        .catch(reject);
    });
  }

  /**
   * 更新项目版本信息
   * @param {String} versionId 项目版本id
   * @param {Object} options 更新信息
   * @return {Promise}
   */
  updateVersion(versionId, options) {
    return new Promise((resolve, reject) => {
      this.creator.login()
        .then(() => {
          const url = `${testerURI}/project-versions/${versionId}.json`;
          return request.put({
            url,
            headers: { Authorization: `Bearer ${this.creator.token.accessToken}` },
            body: options,
            json: true,
          });
        })
        .then(() => this.creator.logout())
        .then(() => {
          resolve();
        })
        .catch(reject);
    });
  }

  /**
   * 冻结项目版本
   * @param {String} versionId 项目版本id
   * @return {Promise}
   */
  freezeVersion(versionId) {
    return this.updateVersion(versionId, { unitTest: { status: statusKind.frozen } });
  }

  /**
   * 随机冻结项目版本
   * @param {Array} versions 项目版本列表
   * @return {Promise}
   */
  randomFreezeVersions(versions) {
    return new Promise((resolve, reject) => {
      let count = 0;
      this.creator.login()
        .then(() => {
          const promises = versions.map((version) => {
            if (Math.random() < 0.5 || count > 0) {
              return Promise.resolve();
            }
            count += 1;
            const status = statusKind.frozen;
            const url = `${testerURI}/project-versions/${version.versionId}.json`;
            return request.put({
              url,
              headers: { Authorization: `Bearer ${this.creator.token.accessToken}` },
              body: { unitTest: { status } },
              json: true,
            });
          });
          return Promise.all(promises);
        })
        .then(() => this.creator.logout())
        .then(resolve)
        .catch(reject);
    });
  }

  /**
   * 获取随机项目信息
   * @param {String} language 语言
   * @return {Object}
   */
  static getRandomProjectInfo(language = 'c') {
    return {
      projectName: randomstring.generate(16),
      initVersion: randomstring.generate(6),
      language,
      projectType: 'gcc',
      description: randomstring.generate(100),
    };
  }
}

/**
 * Export model definition object.
 */
module.exports = Project;
